<?php
// Copyright 2019 Hackware SpA <human@hackware.cl>
// This file is part of "Hackware Web Services Payment" and licensed under
// the terms of the GNU Affero General Public License version 3, or (at your
// option) a later version. You should have received a copy of this license
// along with the software. If not, see <https://www.gnu.org/licenses/>.

namespace Hawese\Payment\Gateways;

use Hawese\Payment\Payment;
use Hawese\Payment\Exceptions\UnexpectedResponseException;
use Hawese\Payment\Support\Http as HttpSupport;
use Illuminate\Support\Str;
use Psr\Http\Message\ResponseInterface;

class FlowGateway extends AbstractGateway
{
    public function purchase(array $bodyParams): array
    {
        $bodyParams = $this->purchaseAddDefaultParams($bodyParams);
        $response = $this->request('POST', '/payment/create', $bodyParams);
        $responseBody = $this->purchaseProcessResponse($response);

        $this->purchaseInsertPayment($bodyParams, $responseBody);

        $redirectUrl = $responseBody->url . '?token=' . $responseBody->token;
        return ['redirect_url' => $redirectUrl];
    }

    private function purchaseAddDefaultParams(array $bodyParams): array
    {
        $uuid = (string) Str::uuid();

        return array_merge($bodyParams, [
            'urlReturn' => HttpSupport::appendQueryParams(
                config('payment.return_url'),
                ['uuid' => $uuid]
            ),
            'urlConfirmation' => url(route(
                'gateways.notify',
                ['gateway' => 'flow']
            )),
            'commerceOrder' => $uuid,
        ]);
    }

    /**
     * Validate and process $response
     * @returns object parsed body
     */
    private function purchaseProcessResponse(
        ResponseInterface &$response
    ): object {
        if ($response->getStatusCode() == 200) {
            $responseBody = HttpSupport::getJsonBody($response);

            if (property_exists($responseBody, 'token')) {
                return $responseBody;
            }
        }

        throw new UnexpectedResponseException($response);
    }

    /**
     * @returns string Payment primary key value
     */
    private function purchaseInsertPayment(
        array &$bodyParams,
        object &$responseBody
    ): string {
        return (new Payment([
            'uuid' => $bodyParams['commerceOrder'],
            'user_uid' => $bodyParams['email'],
            'gateway' => 'flow',
            'currency' => $bodyParams['currency'] ?? 'CLP',
            'amount' => $bodyParams['amount'], // Integers only!!
            'description' => $bodyParams['subject'],
            'detail' => json_encode([
                'flowOrder' => $responseBody->flowOrder,
                'paymentMethod' => $bodyParams['paymentMethod'],
            ]),
            'status' => Payment::STATUS_PENDING,
        ]))->insert();
    }

    public function acceptNotification(array $bodyParams)
    {
        $queryParams = ['token' => $bodyParams['token']];
        $response = $this->request(
            'GET',
            '/payment/getStatus?' . HttpSupport::buildUriQuery($queryParams)
        );
        $responseBody = HttpSupport::getJsonBody($response);

        $payment = Payment::find($responseBody->commerceOrder);
        if ($payment->status === Payment::STATUS_COMPLETED) {
            return response('Already processed', 400);
        } else {
            // 1 pendiente de pago, 2 pagada, 3 rechazada, 4 anulada
            $payment->validateAndUpdateStatus($responseBody->status, [2], [1]);
        }
    }
}
